package it.unicam.ids.pvm.distributore;

import it.unicam.ids.pvm.data.CasellaDAO;
import it.unicam.ids.pvm.data.DAOException;
import it.unicam.ids.pvm.data.DAOFactory;
import it.unicam.ids.pvm.data.ProdottoDAO;

import java.util.HashMap;

/**
 * La classe rappresenta l'espositore comprendente le caselle del distributore.
 * Implementa il design pattern Singelton. Contiene i seguenti attributi:
 * instance, istanza della classe; caselle, lista delle caselle contenute.
 * 
 * @author Luca Iachini, Valerio Iachini, Alessandro Cardenà
 * 
 */
public class Espositore {

	private static Espositore instance;
	private HashMap<String, Casella> caselle;
	private CasellaDAO casellaDAO;
	private ProdottoDAO prodottoDAO;

	/**
	 * Il metodo restituisce l'istanza relativa alla classe espositore.
	 * 
	 * @return instance.
	 * @throws DAOException.
	 */

	public static Espositore getInstance() throws DAOException {
		if (instance == null) {
			instance = new Espositore();
		}
		return instance;
	}

	/**
	 * Costruttore della classe. Inizializza la lista delle caselle esposte.
	 * 
	 * @throws DAOException.
	 */

	private Espositore() throws DAOException {
		caselle = new HashMap<String, Casella>();
		DAOFactory df = DAOFactory.getDAOFactory();
		casellaDAO = df.getCasellaDAO();
		prodottoDAO = df.getProdottoDAO();
		Casella[] caselleCaricate = casellaDAO.findAllCaselle();
		for (Casella casella : caselleCaricate) {
			if (casella != null)
				caselle.put(casella.getEtichetta(), casella);
		}
	}

	/**
	 * Il metodo consente di aggiungere un prodotto in una casella, aggiornando
	 * la tabella relativa alle caselle nel database. Se il prodotto non è
	 * presente del databse, viene inserito.
	 * 
	 * @param etichetta
	 *            codice della casella su cui inserire il prodotto scelto.
	 * @param prodotto
	 *            prodotto da inserire.
	 * @param quantita
	 *            quantità del prodotto inserita.
	 * @throws Exception
	 *             messaggio d'errore relativo alla validità dell'etichetta.
	 */

	public void aggiungiProdotto(String etichetta, Prodotto prodotto,
			int quantita) throws Exception {
		Casella casella = caselle.get(etichetta);
		if (casella != null) {
			Prodotto p = ricercaProdotto(prodotto.getCodice());
			if (p == null) {
				p = prodotto;
				prodottoDAO.insert(p);
			}
			casella.setProdotto(p);
			casella.setQuantita(quantita);
			casellaDAO.update(casella, casella.getEtichetta());
		} else
			throw new Exception(
					"L'etichetta specificata non è associata a nessuna casella");
	}

	/**
	 * Il metodo consente di rimuovere un prodotto da una casella.
	 * 
	 * @param etichetta
	 *            Etichetta della casella contenente il prodotto da eliminare.
	 * @throws DAOException.
	 */

	public void rimuoviProdottoCasella(String etichetta) throws DAOException {
		Casella casella = caselle.get(etichetta);
		Prodotto prodotto = casella.getProdotto();
		casellaDAO.delete(casella);
		if (prodottoDAO.canDelete(prodotto.getCodice()))
			prodottoDAO.delete(prodotto);
	}

	/**
	 * Il metodo consente di rimuovere un prodotto.
	 * 
	 * @param codie
	 *            codice del prodotto da eliminare.
	 * @throws DAOException.
	 */

	public void rimuoviProdotto(String codice) throws DAOException {
		Prodotto p = prodottoDAO.findByCodice(codice);
		if (p == null)
			return;
		for (Casella casella : caselle.values()) {
			if (casella.getProdotto() != null
					&& casella.getProdotto().getCodice().equals(codice)) {
				casella.setProdotto(null);
			}
		}
		prodottoDAO.delete(p);
	}

	/**
	 * Il metodo consente di cercare un prodotto all'interno di ogni casella.
	 * 
	 * @param codiceProdotto
	 *            codice del prodotto cercato.
	 * @return prodotto prodotto cercato.
	 * @throws DAOException
	 */
	public Prodotto ricercaProdotto(String codiceProdotto) throws DAOException {
		for (Casella c : caselle.values()) {
			if (c.getProdotto() != null
					&& c.getProdotto().getCodice().equals(codiceProdotto))
				return c.getProdotto();
		}
		return null;
	}

	/**
	 * Il metodo consente di modificare la quantità di un prodotto, in una
	 * casella. La casella viene aggiornata nella relativa tabella del database.
	 * 
	 * @param etichetta
	 *            codice della casella contenente il prodotto da incrementare.
	 * @param quantita
	 *            quantità da incrementare.
	 * @throws Exception.
	 */

	public void ricaricaProdotto(String etichetta, int quantita)
			throws Exception {// TODO
		Casella casella = caselle.get(etichetta);
		casella.setQuantita(quantita);
		casellaDAO.update(casella, casella.getEtichetta());
	}

	/**
	 * Il metodo consente di aggiungere una casella alla lista e alla relativa
	 * tabella del database. Se la casella contiene un prodotto, questo verrà
	 * inserito nella relativa tabella del database.
	 * 
	 * @param casella
	 *            casella da aggiungere.
	 * @throws DAOException.
	 */

	public void addCasella(Casella casella) throws DAOException {
		caselle.put(casella.getEtichetta(), casella);
		Prodotto p = casella.getProdotto();
		if (p != null && prodottoDAO.findByCodice(p.getCodice()) == null)
			prodottoDAO.insert(p);
		casellaDAO.insert(casella);
	}

	/**
	 * Il metodo restituisce la casella selezionata.
	 * 
	 * @param etichetta
	 *            codice della casella scelta.
	 * @return casella.
	 */

	public Casella getCasella(String etichetta) {
		return caselle.get(etichetta);
	}

	/**
	 * Il metodo consente di rimuovere una casella.
	 * 
	 * @param etichetta
	 *            codice della casella da rimuovere.
	 * @throws DAOException.
	 */

	public void rimuoviCasella(String etichetta) throws DAOException {
		Casella c = caselle.remove(etichetta);
		if (c != null)
			casellaDAO.delete(c);
	}

	/**
	 * Il metodo consente di aggiornare una casella
	 * 
	 * @param casella
	 *            dati aggiornati della casella.
	 * @param oldEtichetta
	 *            l'etichetta della casella da aggiornare.
	 * @throws DAOException.
	 */

	public void updateCasella(Casella casella, String oldEtichetta)
			throws DAOException {
		casellaDAO.update(casella, oldEtichetta);
		if (caselle.remove(oldEtichetta) != null) {
			caselle.put(casella.getEtichetta(), casella);
		}
	}

	/**
	 * Il metodo consente di aggiornare un prodotto
	 * 
	 * @param prodotto
	 *            dati aggiornati del prodotto.
	 * @param oldCodice
	 *            codice del prodotto da aggiornare.
	 * @throws DAOException.
	 */

	public void updateProdotto(Prodotto prodotto, String oldCodice)
			throws DAOException {

		Prodotto p = ricercaProdotto(oldCodice);
		if (p != null) {
			prodottoDAO.update(prodotto, oldCodice);
			p.setCodice(prodotto.getCodice());
			p.setDescrizione(prodotto.getDescrizione());
			p.setIngredienti(prodotto.getIngredienti());
			try {
				p.setPrezzo(prodotto.getPrezzo());
				p.setPromozine(prodotto.getPromozione());
			} catch (Exception e) {
			}
			p.setValoriNutrizionali(prodotto.getValoriNutrizionali());
		} else {
			p = prodottoDAO.findByCodice(oldCodice);
			if (p != null) {
				prodottoDAO.update(prodotto, oldCodice);
			}
		}
	}

	/**
	 * Il metodo restituisce l'array contenente le caselle.
	 * 
	 * @return caselle.
	 */

	public Casella[] getCaselle() {
		return (Casella[]) caselle.values().toArray(new Casella[0]);
	}

}